package org.store.dao;

import org.apache.log4j.Logger;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.transaction.annotation.Transactional;
import org.store.domain.Product;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ProductDao extends AbstractDao<Product> {

    private static Logger log = Logger.getLogger(ProductDao.class);

    @Override
    public Product getById(long id) throws DaoException {
        try {
            return jdbcTemplate.queryForObject("select product_id, title, price, amount, image_id, category_id from product where product_id = ?", MAPPER, id);
        } catch (DataAccessException e) {
            throw new DaoException("Cannot get product with id = " + id, e);
        }
    }

    public List<Product> getByTitle(String title) throws DaoException {
        try {
            return jdbcTemplate.query("select product_id, title, price, amount, image_id, category_id from product where title = ?", MAPPER, title);
        } catch (DataAccessException e) {
            throw new DaoException("Cannot get product with title = " + title, e);
        }
    }

    public List<Product> getByCategoryId(long categoryId) throws DaoException {
        try {
            return jdbcTemplate.query("select product_id, title, price, amount, image_id, category_id from product where category_id = ?", MAPPER, categoryId);
        } catch (DataAccessException e) {
            throw new DaoException("Cannot get product with category = " + categoryId, e);
        }
    }

    //todo : test getByCategoryIds
    public List<Product> getByCategoryIds(List<Long> categoryIds) throws DaoException {
        List<Product> products = new ArrayList<>();
        if (categoryIds == null)
            throw new IllegalArgumentException("List cannot be null");
        for (Long categoryId : categoryIds) {
            products.addAll(getByCategoryId(categoryId));
        }
        return products;
    }

    public List<Product> getByCategoryIds1(List<Long> categoryIds) throws DaoException {
        Map<String, Object> params = new HashMap();
        params.put("ids", categoryIds);
        return jdbcTemplate.query("select product_id, title, price, amount, image_id, category_id from product where category_id in (:ids)", MAPPER, params);
    }

    public List<Product> getAll(int start, int limit) throws DaoException {
        try {
            return jdbcTemplate.query("select product_id, title, price, amount, image_id, category_id from product order by 1 offset ? limit ?", MAPPER, start, limit);
        } catch (DataAccessException e) {
            throw new DaoException("Cannot get all products", e);
        }
    }

    @Override
    @Transactional
    public Product save(Product product) throws DaoException {
        if (product == null)
            throw new IllegalArgumentException("Product cannot be null");
        try {
            long id = jdbcTemplate.queryForLong("insert into product (title, price, amount, image_id, category_id) values(?,?,?,?,?) returning product_id", product.getTitle(), product.getPrice(),
                    product.getAmount(), product.getImageId(), product.getCategoryId());
            product.setId(id);
            return product;
        } catch (DataAccessException e) {
            throw new DaoException("Cannot save product with id = " + product.getId(), e);
        }
    }

    @Override
    public boolean delete(Product product) throws DaoException {
        try {
            int updated = jdbcTemplate.update("delete from product where product_id = ?", product.getId());
            return updated > 0;
        } catch (DataAccessException e) {
            throw new DaoException("Cannot delete product with id = " + product.getId(), e);
        }
    }

    @Override
    public Product saveOrUpdate(Product product) throws DaoException {
        if (product.getId() == null) {
            return save(product);
        }
        try {
            jdbcTemplate.update("update product SET title = ?, price = ?, amount = ?, image_id = ?, category_id = ? where product_id = ?", product.getTitle(),
                    product.getPrice(), product.getAmount(), product.getImageId(), product.getCategoryId(), product.getId());
            return product;
        } catch (DataAccessException e) {
            throw new DaoException("Cannot update product with id = " + product.getId(), e);
        }
    }


    @Override
    @Transactional
    public List<Product> saveAll(final List<Product> products) throws DaoException {
        if (products == null)
            throw new IllegalArgumentException("List cannot be null");
        for (Product product : products) {
            save(product);
        }
        return products;
    }

    @Override
    public boolean isExists(long id) throws DaoException {
        try {
            return jdbcTemplate.queryForLong("select count(*) from product where product_id = ?", id) > 0;
        } catch (DataAccessException e) {
            throw new DaoException("Cannot get product with id = " + id, e);
        }
    }

    private static final RowMapper<Product> MAPPER = new RowMapper<Product>() {
        public Product mapRow(ResultSet rs, int rowNum) throws SQLException {
            Product product = new Product(rs.getString("title"), rs.getInt("price"), rs.getInt("amount"), rs.getInt("image_id"), rs.getLong("category_id")); //TODO:FIX
            product.setId(rs.getLong("product_id"));
            return product;
        }
    };
}
